#define xuser mixc::powerful_cat
#include"docker/page_array.hpp"
#include"lang/cxx/clone.hpp"
#include"lang/cxx.hpp"
#include"mixc.hpp"
#include"utils/counter.hpp"
#include"utils/memory.hpp"
#include"utils/static_length_of.hpp"
#include"utils/temp_allocator.hpp"

xinit(xuser::the_main){
    using namespace xuser;

    counter demo;

    // 版本一
    // 注意：
    // 由于这里是静态内存分配，而且每次返回的地址是一样的
    // 所以是新值覆盖旧值的逻辑
    {
        xhint(demo);
        char buf[128];
        auto alloc          = [&/*引用捕获*/](uxx){
            // 返回 buf

            // 总是返回首地址
            // 所以每一个 clone 的字符串都是使用同一片内存空间
            // 这样就会让新值覆盖旧值

            // 此外：
            // 需要注意 buf 的生命周期，由于 buf 是 the_main 模块的局部变量
            // 所以作用域只能在当前函数的范围，这也限定了此 lambda 只能在当前函数中使用
            // 
            // 一般只需要记住：
            // 如果 lambda 通过引用了局部变量，那么这个 lambda 也会变成仅限局部可用
            return buf;
        };

        auto origin_str     = c08{"hello"};
        auto v0             = origin_str.clone(alloc);
        auto p_origin       = voidp(origin_str.operator char *());
        auto p_v0           = voidp(v0.operator char *());
        auto p_buf          = voidp(buf);

        // 可以看到 p_origin 和 p_v 指向的地址不一样
        xhint(origin_str, v0, p_origin, p_v0);

        // 可以看到 p_v 和 p_buf 是同一个地址
        xhint(p_v0, p_buf);

        auto other_str      = c08{"oh~"};

        // 仍然通过 alloc 分配
        auto v1             = other_str.clone(alloc);
        auto p_v1           = voidp(v1.operator char *());
        auto p_other_str    = voidp(other_str.operator char *());

        // 可以看到 other_str="oh~" v1="0h~"
        xhint(other_str, p_other_str);

        // v0 由于和 v1 是从相同的地址开始存放内存，所以 v0 所表示的字符串就失效了
        // 但是 v0 的长度不会随着更改，所以后边可能会出现多余的字符
        xhint(v1, p_v1, v0, p_v0);
    }

    // 分割线 -----------------------------------------------------------------------
    // 版本二
    // 假如我们想要保留原来的字符串可以怎么做呢？
    // 顺便思考一下版本二有什么问题？
    {
        xhint(demo);

        // 我们更新一下分配器逻辑
        // 让 p_mem 指向的 buf 缓冲区
        char buf[128];
        auto p_mem          = buf;
        auto alloc          = [&](uxx length){
            // 保存当前地址
            auto available  = p_mem;

            // p_mem 消耗 length 个长度的内存
            p_mem          += length;

            // [available, available + length) 范围为可用的缓冲区地址
            // 返回首地址
            return available;
        };
        
        auto origin         = c08{"小猫欢迎您！"};
        auto v0             = origin.clone(alloc);
        auto v1             = origin.clone(alloc);
        auto p_origin       = voidp(origin.operator char *());
        auto p_v0           = voidp(v0.operator char *());
        auto p_v1           = voidp(v1.operator char *());

        // 可以看到内容都是一样的
        xhint(origin, v0, v1);

        // 但是实际的地址是不一样的
        xhint(p_origin, p_v0, p_v1);

        auto v2             = c08{"wellcome"}.clone(alloc);

        // 可以看到 v0,v1没有受到 v2 的影响
        xhint(v0, v1, v2);
    }

    // 分割线 -----------------------------------------------------------------------
    // 版本三
    // 版本二存在缓冲区溢出的问题，如果我们可以准确估算出分配的内存一定在某个范围内
    // 那这种方式是比较高效的，如果分配的内存大小不固定那么版本二的适用范围就有一定限制
    {
        xhint(demo);
        auto origin         = c08{"[抗疫符] 天灵灵，地灵灵，疫情退散~"};

        // 这里使用动态内存分配
        auto v0             = origin.clone(memory::default_alloc<char/*分配 char 数组*/>);
        auto v1             = origin.clone(memory::default_alloc<char>);
        auto v2             = origin.clone(memory::default_alloc<char>);
        auto p_v0           = voidp(v0.operator char *());
        auto p_v1           = voidp(v1.operator char *());
        auto p_v2           = voidp(v2.operator char *());

        // 可以看到每一个副本都是有独立的一块内存
        xhint(p_v0, v0);
        xhint(p_v1, v1);
        xhint(p_v2, v2);

        // 使用动态内存分配不要忘记手动释放内存
        memory::default_free<char>((char *)v0, v0->length);
        memory::default_free<char>((char *)v1, v1->length);
        memory::default_free<char>((char *)v2, v2->length);
    }

    // 分割线 -----------------------------------------------------------------------
    // 版本四
    // 可以通过融合栈内存和堆内存，将静态分配和动态分配的优点融于一体
    {
        xhint(demo);

        // 动态数组
        auto && list        = page_array<c08>{};
        char buf[256];
        auto p_mem          = buf;
        auto alloc          = [&](uxx length){
            // 如果 buf 静态内存不够分配了，就使用动态内存
            if (p_mem + length > buf + static_length_of(buf)){
                auto mem    = memory::default_alloc<char>(length);

                // 保存记录
                list.push(c08{ mem/*地址*/, length/*长度信息*/ });

                // 返回动态内存
                return mem;
            }

            // 保存当前地址
            auto available  = p_mem;

            // p_mem 消耗 length 个长度的内存
            p_mem          += length;

            // [available, available + length) 范围为可用的缓冲区地址
            // 返回首地址
            return available;
        };

        auto origin         = c08{"[抗疫符+] 天灵灵，地灵灵，疫情退散，世界和谐~"};

        for(uxx i = 0; i < 64; i++){
            auto helper     = origin.clone(alloc);
            auto p_helper   = voidp(helper.operator char *());
            xhint(p_helper, helper); // 每次地址都不一样
        }

        // 批量释放
        list.foreach([](auto item){
            auto free       = voidp(item.operator char *());
            xhint(free);
            memory::default_free<char>((char *)free, item->length);
        });
    }

    // 分割线 -----------------------------------------------------------------------
    // 版本五
    // 简化，使用 temp_allocator 自动释放内存
    {
        // 动态数组
        char buf[256];
        auto allocator      = temp_allocator{}; // 只能在当前作用域使用
        auto alloc          = allocator.item_as<char>();
        auto p_mem          = buf;
        auto alloc          = [&](uxx length){
            // 如果 buf 静态内存不够分配了，就使用动态内存
            if (p_mem + length > buf + static_length_of(buf)){
                auto mem    = alloc(length);

                // 返回动态内存
                return mem;
            }

            // 保存当前地址
            auto available  = p_mem;

            // p_mem 消耗 length 个长度的内存
            p_mem          += length;

            // [available, available + length) 范围为可用的缓冲区地址
            // 返回首地址
            return available;
        };

        auto origin         = c08{"[抗疫符+] 天灵灵，地灵灵，疫情退散，世界和谐~"};

        for(uxx i = 0; i < 64; i++){
            auto helper     = origin.clone(alloc);
            auto p_helper   = voidp(helper.operator char *());
            xhint(p_helper, helper); // 每次地址都不一样
        }
    } // 退出作用域 allcator 会自动释放分配的内存
};
